#pragma once

namespace helper {

class IOpenable{
public:
	virtual ~IOpenable(){}
	virtual bool open()  = 0;
	virtual bool close() = 0;
	virtual bool isOpened() const = 0;
};

class Openable : public IOpenable{
public:
	~Openable() override {}
	bool open() override {
		if(!isOpened()){
			bool ret = _open();
			if(ret){
				_isOpened = true;
			}
			return ret;
		}
		return true;
	}
	bool close() override {
		if(isOpened()){
			bool ret = _close();
            if(ret){
                _isOpened = false;
            }
            return ret;
		}
        return true;
	}
	bool isOpened() const override {
		return _isOpened;
	}
protected:
	virtual bool _open() = 0;
	virtual bool _close() = 0;
private:
	bool _isOpened = false;
};

class RefCountOpenable : public IOpenable {
public:
	~RefCountOpenable() override {}

    bool isOpened() const override {
        return opened_  > 0;
    };
    bool open() override {
        if(opened_ < 0) return false;

        if(opened_++ == 0){
            return _open();
        }
        return false;
    }
    bool close() override {
        if(opened_ < 0) return false;

        if(--opened_ == 0){
            return _close();
        }
        return false;
    }

protected:
	virtual bool _open() = 0;
	virtual bool _close() = 0;
private:
    int opened_ = 0;
};

}//end namespace helper
